# install dplyr
install.packages("dplyr")
Error in install.packages : Updating loaded packages
install.packages("ggplot2")
Error in install.packages : Updating loaded packages
#load in dplyr
library(dplyr)
library(ggplot2)
library(datasets)
# read the csv files
lahman_people <- read.csv("lahman_people.csv")
savant_data <- read.csv("savant_data_2021_2023.csv")
head(lahman_people)
head(savant_data)
plate_appearances <-
# start with the savant data
savant_data %>%
# we will group by batter, season, game, and at bat and preserve the
group_by(
batter,
game_year,
game_pk,
at_bat_number
) %>%
summarise() %>%
ungroup() %>%
# now we have just unique batter, season, game, and at bat observations
# but, we need to count how many of those there are each season
# so, we will do another group by and summarise
group_by(
batter,
game_year
) %>%
summarise(
# the n() function counts the number of unique observations we have
playing_time = n()
) %>%
ungroup()
`summarise()` has grouped output by 'batter', 'game_year', 'game_pk'. You can override using the `.groups` argument.`summarise()` has grouped output by 'batter'. You can override using the `.groups` argument.
plate_appearances
pa_in_year <- plate_appearances %>%
group_by(batter) %>%
summarise(
pa_2021 = sum(playing_time[game_year == 2021], na.rm = TRUE), # Plate appearances for 2021
pa_2022 = sum(playing_time[game_year == 2022], na.rm = TRUE), # Plate appearances for 2022
pa_2023 = sum(playing_time[game_year == 2023], na.rm = TRUE) # Plate appearances for 2023
) %>%
mutate(
pa_avg = round(rowMeans(select(., pa_2021, pa_2022, pa_2023), na.rm = TRUE)) # Calculate row-wise mean
)
pa_in_year
NA
pa_in_year <- pa_in_year %>%
mutate(
# Is there a steady decrease in plate appearances?
# Calculate percentage decrease between 2021 and 2022
decrease_21_22 = (pa_2021 - pa_2022) / pa_2021,
# Calculate percentage decrease between 2022 and 2023
decrease_22_23 = (pa_2022 - pa_2023) / pa_2022,
# Check if both decreases are at least 15%
decreasing = if_else(
decrease_21_22 >= 0.15 & decrease_22_23 >= 0.15,
1,
0,
2 # likely got injured or underperformed (# -> 0)
),
# Is there a steady increase in plate appearances?
# Calculate percentage increase between 2021 and 2022
increase_21_22 = (pa_2022 - pa_2021) / pa_2021,
# Calculate percentage increase between 2022 and 2023
increase_22_23 = (pa_2023 - pa_2022) / pa_2022,
# Check if both increases are at least 15%
increasing = if_else(
increase_21_22 >= 0.15 & increase_22_23 >= 0.15,
1,
0,
2 # likely a rookie or comeback from injury (0 -> #)
),
# Is the amount of plate appearances constant within 15%
constant = if_else(
# if it is increasing or decreasing, then it is not constant
(increasing == 1) | (decreasing == 1),
0,
if_else(
# If EITHER difference has an increase or decrease from 0%-15%, it is roughly constant
(((increase_21_22 < 0.15) & (increase_21_22 > 0)) |
((decrease_21_22 < 0.15) & (decrease_21_22 > 0))) &
(((increase_22_23 < 0.15) & (increase_22_23 > 0)) |
((decrease_22_23 < 0.15) & (decrease_22_23 > 0))),
# if both differences are less than a 15% change it is roughly constant
1,
0
)
)
) %>%
# Optionally, remove intermediate columns
select(-decrease_21_22, -decrease_22_23, -increase_21_22, -increase_22_23)
pa_in_year
plot(pa_in_year$pa_2021, pa_in_year$pa_2022,
pch = 19,
cex = 2,
col = if_else(pa_in_year$decreasing == 1 | pa_in_year$decreasing == 2,
"red",
if_else(pa_in_year$increasing == 1 | pa_in_year$increasing == 2,
"#3d943c",
if_else(pa_in_year$constant == 1,
"blue",
"black"))))

plot(pa_in_year$pa_2022, pa_in_year$pa_2023,
pch = 19,
cex = 1.5,
col = if_else(pa_in_year$decreasing == 1,
"red",
if_else(pa_in_year$increasing == 1,
"#3d943c",
if_else(pa_in_year$constant == 1,
"blue",
"black"))))

summary(factor(pa_in_year$decreasing))
0 1 2
696 125 518
summary(factor(pa_in_year$increasing))
0 1 2
1112 115 112
summary(factor(pa_in_year$constant))
0 1
1285 54
batters_faced <-
# start with the savant data
savant_data %>%
# we will group by batter, season, game, and at bat and preserve the
group_by(
pitcher,
game_year,
game_pk,
at_bat_number
) %>%
summarise() %>%
ungroup() %>%
# now we have just unique batter, season, game, and at bat observations
# but, we need to count how many of those there are each season
# so, we will do another group by and summarise
group_by(
pitcher,
game_year
) %>%
summarise(
# the n() function counts the number of unique observations we have
playing_time = n()
) %>%
ungroup()
`summarise()` has grouped output by 'pitcher', 'game_year', 'game_pk'. You can override using the `.groups` argument.`summarise()` has grouped output by 'pitcher'. You can override using the `.groups` argument.
batters_faced
plot(factor(batters_faced$game_year), batters_faced$playing_time, cex = 0.5)

bf_in_year <- batters_faced %>%
group_by(pitcher) %>%
summarise(
bf_2021 = sum(playing_time[game_year == 2021], na.rm = TRUE), # batters faced for 2021
bf_2022 = sum(playing_time[game_year == 2022], na.rm = TRUE), # batters faced for 2022
bf_2023 = sum(playing_time[game_year == 2023], na.rm = TRUE) # batters faced for 2023
) %>%
mutate(
bf_avg = round(rowMeans(select(., bf_2021, bf_2022, bf_2023), na.rm = TRUE)) # Calculate row-wise mean
)
bf_in_year
bf_in_year <- bf_in_year %>%
mutate(
# Calculate percentage decrease between 2021 and 2022
decrease_21_22 = (bf_2021 - bf_2022) / bf_2021,
# Calculate percentage decrease between 2022 and 2023
decrease_22_23 = (bf_2022 - bf_2023) / bf_2022,
# Check if both decreases are at least 15%
decreasing = if_else(
decrease_21_22 >= 0.15 & decrease_22_23 >= 0.15,
1,
0,
2 # likely injured or under-performed (# -> 0)
),
# Calculate percentage increase between 2021 and 2022
increase_21_22 = (bf_2022 - bf_2021) / bf_2021,
# Calculate percentage increase between 2022 and 2023
increase_22_23 = (bf_2023 - bf_2022) / bf_2022,
# Check if both increases are at least 15%
increasing = if_else(
increase_21_22 >= 0.15 & increase_22_23 >= 0.15,
1,
0,
2 # likely rookie or comeback player (0 -> #)
),
# Is the amount of batters faced constant within 15%
constant = if_else(
# if it is increasing or decreasing, then it is not constant
(increasing == 1) | (decreasing == 1),
0,
if_else(
# If EITHER difference has an increase or decrease from 0%-15%, it is roughly constant
(((increase_21_22 < 0.15) & (increase_21_22 > 0)) |
((decrease_21_22 < 0.15) & (decrease_21_22 > 0))) &
(((increase_22_23 < 0.15) & (increase_22_23 > 0)) |
((decrease_22_23 < 0.15) & (decrease_22_23 > 0))),
# if both differences are less than a 15% change it is roughly constant
1,
0
)
)
) %>%
# Optionally, remove intermediate columns
select(-decrease_21_22, -decrease_22_23, -increase_21_22, -increase_22_23)
bf_in_year
plot(bf_in_year$bf_2021, bf_in_year$bf_2022,
pch = 19,
cex = 2,
col = if_else(bf_in_year$decreasing == 1 | bf_in_year$decreasing == 2,
"red",
if_else(bf_in_year$increasing == 1 | bf_in_year$increasing == 2,
"#3d943c",
if_else(bf_in_year$constant == 1,
"blue",
"black"))))

plot(bf_in_year$bf_2022, bf_in_year$bf_2023,
pch = 19,
cex = 2,
col = if_else(bf_in_year$decreasing == 1,
"red",
if_else(bf_in_year$increasing == 1,
"#3d943c",
if_else(bf_in_year$constant == 1,
"blue",
"black"))))

summary(factor(bf_in_year$decreasing))
0 1 2
993 137 253
summary(factor(bf_in_year$increasing))
0 1 2
1026 142 215
summary(factor(bf_in_year$constant))
0 1
1331 52
LS0tCnRpdGxlOiAiUmVkcyBIYWNrYXRob24gMjAyNSIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKYGBge3J9CiMgaW5zdGFsbCBkcGx5cgoKaW5zdGFsbC5wYWNrYWdlcygiZHBseXIiKQppbnN0YWxsLnBhY2thZ2VzKCJnZ3Bsb3QyIikKYGBgCgpgYGB7cn0KI2xvYWQgaW4gZHBseXIKCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShkYXRhc2V0cykKYGBgCgpgYGB7cn0KIyByZWFkIHRoZSBjc3YgZmlsZXMKCmxhaG1hbl9wZW9wbGUgPC0gcmVhZC5jc3YoImxhaG1hbl9wZW9wbGUuY3N2IikKc2F2YW50X2RhdGEgPC0gcmVhZC5jc3YoInNhdmFudF9kYXRhXzIwMjFfMjAyMy5jc3YiKQpgYGAKCmBgYHtyfQpoZWFkKGxhaG1hbl9wZW9wbGUpCmhlYWQoc2F2YW50X2RhdGEpCmBgYAoKYGBge3J9CnBsYXRlX2FwcGVhcmFuY2VzIDwtIAogICAgIyBzdGFydCB3aXRoIHRoZSBzYXZhbnQgZGF0YQogICAgc2F2YW50X2RhdGEgICU+JQogICAgIyB3ZSB3aWxsIGdyb3VwIGJ5IGJhdHRlciwgc2Vhc29uLCBnYW1lLCBhbmQgYXQgYmF0IGFuZCBwcmVzZXJ2ZSB0aGUgCiAgICBncm91cF9ieSgKICAgICAgICBiYXR0ZXIsCiAgICAgICAgZ2FtZV95ZWFyLAogICAgICAgIGdhbWVfcGssCiAgICAgICAgYXRfYmF0X251bWJlcgogICAgKSAlPiUKICAgIHN1bW1hcmlzZSgpICU+JQogICAgdW5ncm91cCgpICU+JQogICAgIyBub3cgd2UgaGF2ZSBqdXN0IHVuaXF1ZSBiYXR0ZXIsIHNlYXNvbiwgZ2FtZSwgYW5kIGF0IGJhdCBvYnNlcnZhdGlvbnMKICAgICMgYnV0LCB3ZSBuZWVkIHRvIGNvdW50IGhvdyBtYW55IG9mIHRob3NlIHRoZXJlIGFyZSBlYWNoIHNlYXNvbgogICAgIyBzbywgd2Ugd2lsbCBkbyBhbm90aGVyIGdyb3VwIGJ5IGFuZCBzdW1tYXJpc2UKICAgIGdyb3VwX2J5KAogICAgICAgIGJhdHRlciwKICAgICAgICBnYW1lX3llYXIKICAgICkgJT4lCiAgICBzdW1tYXJpc2UoCiAgICAgICAgIyB0aGUgbigpIGZ1bmN0aW9uIGNvdW50cyB0aGUgbnVtYmVyIG9mIHVuaXF1ZSBvYnNlcnZhdGlvbnMgd2UgaGF2ZQogICAgICAgIHBsYXlpbmdfdGltZSA9IG4oKQogICAgKSAlPiUKICAgIHVuZ3JvdXAoKQpwbGF0ZV9hcHBlYXJhbmNlcwpgYGAKCmBgYHtyfQpwYV9pbl95ZWFyIDwtIHBsYXRlX2FwcGVhcmFuY2VzICU+JQogIGdyb3VwX2J5KGJhdHRlcikgJT4lCiAgc3VtbWFyaXNlKAogICAgcGFfMjAyMSA9IHN1bShwbGF5aW5nX3RpbWVbZ2FtZV95ZWFyID09IDIwMjFdLCBuYS5ybSA9IFRSVUUpLCAjIFBsYXRlIGFwcGVhcmFuY2VzIGZvciAyMDIxCiAgICBwYV8yMDIyID0gc3VtKHBsYXlpbmdfdGltZVtnYW1lX3llYXIgPT0gMjAyMl0sIG5hLnJtID0gVFJVRSksICMgUGxhdGUgYXBwZWFyYW5jZXMgZm9yIDIwMjIKICAgIHBhXzIwMjMgPSBzdW0ocGxheWluZ190aW1lW2dhbWVfeWVhciA9PSAyMDIzXSwgbmEucm0gPSBUUlVFKSAgIyBQbGF0ZSBhcHBlYXJhbmNlcyBmb3IgMjAyMwogICAgKSAlPiUKICBtdXRhdGUoCiAgICBwYV9hdmcgPSByb3VuZChyb3dNZWFucyhzZWxlY3QoLiwgcGFfMjAyMSwgcGFfMjAyMiwgcGFfMjAyMyksIG5hLnJtID0gVFJVRSkpICMgQ2FsY3VsYXRlIHJvdy13aXNlIG1lYW4KICAgICkKcGFfaW5feWVhcgogIApgYGAKCmBgYHtyfQpwYV9pbl95ZWFyIDwtIHBhX2luX3llYXIgJT4lCiAgbXV0YXRlKAogICAgIyBJcyB0aGVyZSBhIHN0ZWFkeSBkZWNyZWFzZSBpbiBwbGF0ZSBhcHBlYXJhbmNlcz8KICAgICMgQ2FsY3VsYXRlIHBlcmNlbnRhZ2UgZGVjcmVhc2UgYmV0d2VlbiAyMDIxIGFuZCAyMDIyCiAgICBkZWNyZWFzZV8yMV8yMiA9IChwYV8yMDIxIC0gcGFfMjAyMikgLyBwYV8yMDIxLAogICAgIyBDYWxjdWxhdGUgcGVyY2VudGFnZSBkZWNyZWFzZSBiZXR3ZWVuIDIwMjIgYW5kIDIwMjMKICAgIGRlY3JlYXNlXzIyXzIzID0gKHBhXzIwMjIgLSBwYV8yMDIzKSAvIHBhXzIwMjIsCiAgICAjIENoZWNrIGlmIGJvdGggZGVjcmVhc2VzIGFyZSBhdCBsZWFzdCAxNSUKICAgIGRlY3JlYXNpbmcgPSBpZl9lbHNlKAogICAgICBkZWNyZWFzZV8yMV8yMiA+PSAwLjE1ICYgZGVjcmVhc2VfMjJfMjMgPj0gMC4xNSwKICAgICAgMSwKICAgICAgMCwKICAgICAgMiAjIGxpa2VseSBnb3QgaW5qdXJlZCBvciB1bmRlcnBlcmZvcm1lZCAoIyAtPiAwKQogICAgKSwKICAgIAogICAgIyBJcyB0aGVyZSBhIHN0ZWFkeSBpbmNyZWFzZSBpbiBwbGF0ZSBhcHBlYXJhbmNlcz8KICAgICMgQ2FsY3VsYXRlIHBlcmNlbnRhZ2UgaW5jcmVhc2UgYmV0d2VlbiAyMDIxIGFuZCAyMDIyCiAgICBpbmNyZWFzZV8yMV8yMiA9IChwYV8yMDIyIC0gcGFfMjAyMSkgLyBwYV8yMDIxLAogICAgIyBDYWxjdWxhdGUgcGVyY2VudGFnZSBpbmNyZWFzZSBiZXR3ZWVuIDIwMjIgYW5kIDIwMjMKICAgIGluY3JlYXNlXzIyXzIzID0gKHBhXzIwMjMgLSBwYV8yMDIyKSAvIHBhXzIwMjIsCiAgICAjIENoZWNrIGlmIGJvdGggaW5jcmVhc2VzIGFyZSBhdCBsZWFzdCAxNSUKICAgIGluY3JlYXNpbmcgPSBpZl9lbHNlKAogICAgICBpbmNyZWFzZV8yMV8yMiA+PSAwLjE1ICYgaW5jcmVhc2VfMjJfMjMgPj0gMC4xNSwKICAgICAgMSwKICAgICAgMCwKICAgICAgMiAjIGxpa2VseSBhIHJvb2tpZSBvciBjb21lYmFjayBmcm9tIGluanVyeSAoMCAtPiAjKQogICAgKSwKICAgIAogICAgIyBJcyB0aGUgYW1vdW50IG9mIHBsYXRlIGFwcGVhcmFuY2VzIGNvbnN0YW50IHdpdGhpbiAxNSUKICAgIGNvbnN0YW50ID0gaWZfZWxzZSgKICAgICAgIyBpZiBpdCBpcyBpbmNyZWFzaW5nIG9yIGRlY3JlYXNpbmcsIHRoZW4gaXQgaXMgbm90IGNvbnN0YW50CiAgICAgIChpbmNyZWFzaW5nID09IDEpIHwgKGRlY3JlYXNpbmcgPT0gMSksIAogICAgICAgMCwKICAgICAgIGlmX2Vsc2UoCiAgICAgICAgICMgSWYgRUlUSEVSIGRpZmZlcmVuY2UgaGFzIGFuIGluY3JlYXNlIG9yIGRlY3JlYXNlIGZyb20gMCUtMTUlLCBpdCBpcyByb3VnaGx5IGNvbnN0YW50CiAgICAgICAgICgoKGluY3JlYXNlXzIxXzIyIDwgMC4xNSkgJiAoaW5jcmVhc2VfMjFfMjIgPiAwKSkgfCAKICAgICAgICAgICAgKChkZWNyZWFzZV8yMV8yMiA8IDAuMTUpICYgKGRlY3JlYXNlXzIxXzIyID4gMCkpKSAmCiAgICAgICAgICAgKCgoaW5jcmVhc2VfMjJfMjMgPCAwLjE1KSAmIChpbmNyZWFzZV8yMl8yMyA+IDApKSB8IAogICAgICAgICAgICAgICgoZGVjcmVhc2VfMjJfMjMgPCAwLjE1KSAmIChkZWNyZWFzZV8yMl8yMyA+IDApKSksIAogICAgICAgICAjIGlmIGJvdGggZGlmZmVyZW5jZXMgYXJlIGxlc3MgdGhhbiBhIDE1JSBjaGFuZ2UgaXQgaXMgcm91Z2hseSBjb25zdGFudAogICAgICAgICAxLAogICAgICAgICAwCiAgICAgICAgICkKICAgICAgICkKICAgIAogICkgJT4lCiAgIyBPcHRpb25hbGx5LCByZW1vdmUgaW50ZXJtZWRpYXRlIGNvbHVtbnMKICBzZWxlY3QoLWRlY3JlYXNlXzIxXzIyLCAtZGVjcmVhc2VfMjJfMjMsIC1pbmNyZWFzZV8yMV8yMiwgLWluY3JlYXNlXzIyXzIzKQpwYV9pbl95ZWFyCmBgYAoKYGBge3J9CnBsb3QocGFfaW5feWVhciRwYV8yMDIxLCBwYV9pbl95ZWFyJHBhXzIwMjIsCiAgICAgcGNoID0gMTksCiAgICAgY2V4ID0gMiwKICAgICBjb2wgPSBpZl9lbHNlKHBhX2luX3llYXIkZGVjcmVhc2luZyA9PSAxIHwgcGFfaW5feWVhciRkZWNyZWFzaW5nID09IDIsIAogICAgICAgICAgICAgICAgICAgInJlZCIsIAogICAgICAgICAgICAgICAgICAgaWZfZWxzZShwYV9pbl95ZWFyJGluY3JlYXNpbmcgPT0gMSB8IHBhX2luX3llYXIkaW5jcmVhc2luZyA9PSAyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAiIzNkOTQzYyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmX2Vsc2UocGFfaW5feWVhciRjb25zdGFudCA9PSAxLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJibHVlIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiYmxhY2siKSkpKQpwbG90KHBhX2luX3llYXIkcGFfMjAyMiwgcGFfaW5feWVhciRwYV8yMDIzLAogICAgIHBjaCA9IDE5LAogICAgIGNleCA9IDEuNSwKICAgICBjb2wgPSBpZl9lbHNlKHBhX2luX3llYXIkZGVjcmVhc2luZyA9PSAxLCAKICAgICAgICAgICAgICAgICAgICJyZWQiLCAKICAgICAgICAgICAgICAgICAgIGlmX2Vsc2UocGFfaW5feWVhciRpbmNyZWFzaW5nID09IDEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICIjM2Q5NDNjIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZfZWxzZShwYV9pbl95ZWFyJGNvbnN0YW50ID09IDEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImJsdWUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJibGFjayIpKSkpCnN1bW1hcnkoZmFjdG9yKHBhX2luX3llYXIkZGVjcmVhc2luZykpCnN1bW1hcnkoZmFjdG9yKHBhX2luX3llYXIkaW5jcmVhc2luZykpCnN1bW1hcnkoZmFjdG9yKHBhX2luX3llYXIkY29uc3RhbnQpKQpgYGAKCmBgYHtyfQpiYXR0ZXJzX2ZhY2VkIDwtIAogICAgIyBzdGFydCB3aXRoIHRoZSBzYXZhbnQgZGF0YQogICAgc2F2YW50X2RhdGEgICU+JQogICAgIyB3ZSB3aWxsIGdyb3VwIGJ5IGJhdHRlciwgc2Vhc29uLCBnYW1lLCBhbmQgYXQgYmF0IGFuZCBwcmVzZXJ2ZSB0aGUgCiAgICBncm91cF9ieSgKICAgICAgICBwaXRjaGVyLAogICAgICAgIGdhbWVfeWVhciwKICAgICAgICBnYW1lX3BrLAogICAgICAgIGF0X2JhdF9udW1iZXIKICAgICkgJT4lCiAgICBzdW1tYXJpc2UoKSAlPiUKICAgIHVuZ3JvdXAoKSAlPiUKICAgICMgbm93IHdlIGhhdmUganVzdCB1bmlxdWUgYmF0dGVyLCBzZWFzb24sIGdhbWUsIGFuZCBhdCBiYXQgb2JzZXJ2YXRpb25zCiAgICAjIGJ1dCwgd2UgbmVlZCB0byBjb3VudCBob3cgbWFueSBvZiB0aG9zZSB0aGVyZSBhcmUgZWFjaCBzZWFzb24KICAgICMgc28sIHdlIHdpbGwgZG8gYW5vdGhlciBncm91cCBieSBhbmQgc3VtbWFyaXNlCiAgICBncm91cF9ieSgKICAgICAgICBwaXRjaGVyLAogICAgICAgIGdhbWVfeWVhcgogICAgKSAlPiUKICAgIHN1bW1hcmlzZSgKICAgICAgICAjIHRoZSBuKCkgZnVuY3Rpb24gY291bnRzIHRoZSBudW1iZXIgb2YgdW5pcXVlIG9ic2VydmF0aW9ucyB3ZSBoYXZlCiAgICAgICAgcGxheWluZ190aW1lID0gbigpCiAgICApICU+JQogICAgdW5ncm91cCgpCmJhdHRlcnNfZmFjZWQKCnBsb3QoZmFjdG9yKGJhdHRlcnNfZmFjZWQkZ2FtZV95ZWFyKSwgYmF0dGVyc19mYWNlZCRwbGF5aW5nX3RpbWUsIGNleCA9IDAuNSkKYGBgCgpgYGB7cn0KYmZfaW5feWVhciA8LSBiYXR0ZXJzX2ZhY2VkICU+JQogIGdyb3VwX2J5KHBpdGNoZXIpICU+JQogIHN1bW1hcmlzZSgKICAgIGJmXzIwMjEgPSBzdW0ocGxheWluZ190aW1lW2dhbWVfeWVhciA9PSAyMDIxXSwgbmEucm0gPSBUUlVFKSwgIyBiYXR0ZXJzIGZhY2VkIGZvciAyMDIxCiAgICBiZl8yMDIyID0gc3VtKHBsYXlpbmdfdGltZVtnYW1lX3llYXIgPT0gMjAyMl0sIG5hLnJtID0gVFJVRSksICMgYmF0dGVycyBmYWNlZCBmb3IgMjAyMgogICAgYmZfMjAyMyA9IHN1bShwbGF5aW5nX3RpbWVbZ2FtZV95ZWFyID09IDIwMjNdLCBuYS5ybSA9IFRSVUUpICAjIGJhdHRlcnMgZmFjZWQgZm9yIDIwMjMKICAgICkgJT4lCiAgbXV0YXRlKAogICAgYmZfYXZnID0gcm91bmQocm93TWVhbnMoc2VsZWN0KC4sIGJmXzIwMjEsIGJmXzIwMjIsIGJmXzIwMjMpLCBuYS5ybSA9IFRSVUUpKSAjIENhbGN1bGF0ZSByb3ctd2lzZSBtZWFuCiAgICApCmJmX2luX3llYXIKYGBgCgpgYGB7cn0KYmZfaW5feWVhciA8LSBiZl9pbl95ZWFyICU+JQogIG11dGF0ZSgKICAgICMgQ2FsY3VsYXRlIHBlcmNlbnRhZ2UgZGVjcmVhc2UgYmV0d2VlbiAyMDIxIGFuZCAyMDIyCiAgICBkZWNyZWFzZV8yMV8yMiA9IChiZl8yMDIxIC0gYmZfMjAyMikgLyBiZl8yMDIxLAogICAgIyBDYWxjdWxhdGUgcGVyY2VudGFnZSBkZWNyZWFzZSBiZXR3ZWVuIDIwMjIgYW5kIDIwMjMKICAgIGRlY3JlYXNlXzIyXzIzID0gKGJmXzIwMjIgLSBiZl8yMDIzKSAvIGJmXzIwMjIsCiAgICAjIENoZWNrIGlmIGJvdGggZGVjcmVhc2VzIGFyZSBhdCBsZWFzdCAxNSUKICAgIGRlY3JlYXNpbmcgPSBpZl9lbHNlKAogICAgICBkZWNyZWFzZV8yMV8yMiA+PSAwLjE1ICYgZGVjcmVhc2VfMjJfMjMgPj0gMC4xNSwKICAgICAgMSwKICAgICAgMCwKICAgICAgMiAjIGxpa2VseSBpbmp1cmVkIG9yIHVuZGVyLXBlcmZvcm1lZCAoIyAtPiAwKQogICAgKSwKICAgIAogICAgIyBDYWxjdWxhdGUgcGVyY2VudGFnZSBpbmNyZWFzZSBiZXR3ZWVuIDIwMjEgYW5kIDIwMjIKICAgIGluY3JlYXNlXzIxXzIyID0gKGJmXzIwMjIgLSBiZl8yMDIxKSAvIGJmXzIwMjEsCiAgICAjIENhbGN1bGF0ZSBwZXJjZW50YWdlIGluY3JlYXNlIGJldHdlZW4gMjAyMiBhbmQgMjAyMwogICAgaW5jcmVhc2VfMjJfMjMgPSAoYmZfMjAyMyAtIGJmXzIwMjIpIC8gYmZfMjAyMiwKICAgICMgQ2hlY2sgaWYgYm90aCBpbmNyZWFzZXMgYXJlIGF0IGxlYXN0IDE1JQogICAgaW5jcmVhc2luZyA9IGlmX2Vsc2UoCiAgICAgIGluY3JlYXNlXzIxXzIyID49IDAuMTUgJiBpbmNyZWFzZV8yMl8yMyA+PSAwLjE1LAogICAgICAxLAogICAgICAwLAogICAgICAyICMgbGlrZWx5IHJvb2tpZSBvciBjb21lYmFjayBwbGF5ZXIgKDAgLT4gIykKICAgICksCiAgICAKICAgICMgSXMgdGhlIGFtb3VudCBvZiBiYXR0ZXJzIGZhY2VkIGNvbnN0YW50IHdpdGhpbiAxNSUKICAgIGNvbnN0YW50ID0gaWZfZWxzZSgKICAgICAgIyBpZiBpdCBpcyBpbmNyZWFzaW5nIG9yIGRlY3JlYXNpbmcsIHRoZW4gaXQgaXMgbm90IGNvbnN0YW50CiAgICAgIChpbmNyZWFzaW5nID09IDEpIHwgKGRlY3JlYXNpbmcgPT0gMSksIAogICAgICAgMCwKICAgICAgIGlmX2Vsc2UoCiAgICAgICAgICMgSWYgRUlUSEVSIGRpZmZlcmVuY2UgaGFzIGFuIGluY3JlYXNlIG9yIGRlY3JlYXNlIGZyb20gMCUtMTUlLCBpdCBpcyByb3VnaGx5IGNvbnN0YW50CiAgICAgICAgICgoKGluY3JlYXNlXzIxXzIyIDwgMC4xNSkgJiAoaW5jcmVhc2VfMjFfMjIgPiAwKSkgfCAKICAgICAgICAgICAgKChkZWNyZWFzZV8yMV8yMiA8IDAuMTUpICYgKGRlY3JlYXNlXzIxXzIyID4gMCkpKSAmCiAgICAgICAgICAgKCgoaW5jcmVhc2VfMjJfMjMgPCAwLjE1KSAmIChpbmNyZWFzZV8yMl8yMyA+IDApKSB8IAogICAgICAgICAgICAgICgoZGVjcmVhc2VfMjJfMjMgPCAwLjE1KSAmIChkZWNyZWFzZV8yMl8yMyA+IDApKSksIAogICAgICAgICAjIGlmIGJvdGggZGlmZmVyZW5jZXMgYXJlIGxlc3MgdGhhbiBhIDE1JSBjaGFuZ2UgaXQgaXMgcm91Z2hseSBjb25zdGFudAogICAgICAgICAxLAogICAgICAgICAwCiAgICAgICAgICkKICAgICAgICkKICAgIAogICkgJT4lCiAgIyBPcHRpb25hbGx5LCByZW1vdmUgaW50ZXJtZWRpYXRlIGNvbHVtbnMKICBzZWxlY3QoLWRlY3JlYXNlXzIxXzIyLCAtZGVjcmVhc2VfMjJfMjMsIC1pbmNyZWFzZV8yMV8yMiwgLWluY3JlYXNlXzIyXzIzKQpiZl9pbl95ZWFyCmBgYAoKYGBge3J9CnBsb3QoYmZfaW5feWVhciRiZl8yMDIxLCBiZl9pbl95ZWFyJGJmXzIwMjIsCiAgICAgcGNoID0gMTksCiAgICAgY2V4ID0gMiwKICAgICBjb2wgPSBpZl9lbHNlKGJmX2luX3llYXIkZGVjcmVhc2luZyA9PSAxIHwgYmZfaW5feWVhciRkZWNyZWFzaW5nID09IDIsIAogICAgICAgICAgICAgICAgICAgInJlZCIsIAogICAgICAgICAgICAgICAgICAgaWZfZWxzZShiZl9pbl95ZWFyJGluY3JlYXNpbmcgPT0gMSB8IGJmX2luX3llYXIkaW5jcmVhc2luZyA9PSAyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAiIzNkOTQzYyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmX2Vsc2UoYmZfaW5feWVhciRjb25zdGFudCA9PSAxLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJibHVlIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiYmxhY2siKSkpKQpwbG90KGJmX2luX3llYXIkYmZfMjAyMiwgYmZfaW5feWVhciRiZl8yMDIzLAogICAgIHBjaCA9IDE5LAogICAgIGNleCA9IDIsCiAgICAgY29sID0gaWZfZWxzZShiZl9pbl95ZWFyJGRlY3JlYXNpbmcgPT0gMSwgCiAgICAgICAgICAgICAgICAgICAicmVkIiwgCiAgICAgICAgICAgICAgICAgICBpZl9lbHNlKGJmX2luX3llYXIkaW5jcmVhc2luZyA9PSAxLAogICAgICAgICAgICAgICAgICAgICAgICAgICAiIzNkOTQzYyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmX2Vsc2UoYmZfaW5feWVhciRjb25zdGFudCA9PSAxLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJibHVlIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiYmxhY2siKSkpKQpzdW1tYXJ5KGZhY3RvcihiZl9pbl95ZWFyJGRlY3JlYXNpbmcpKQpzdW1tYXJ5KGZhY3RvcihiZl9pbl95ZWFyJGluY3JlYXNpbmcpKQpzdW1tYXJ5KGZhY3RvcihiZl9pbl95ZWFyJGNvbnN0YW50KSkgCmBgYAo=